﻿using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using Mitsubishi;
using Mitsubishi.Base;
using ModbusLib;
using ModbusLib.Base;
using OmronLib;
using OmronLib.Base;
using SecsGemLib;

namespace CommunicationTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("开始执行");
            /* ASCII 转换思路  
             * （1）bin byte => hex char => ascii byte
                   byte: 0x01 0x02 0x03 0x04 
                      过程: select(x=>x.ToString("X2")
                   ascii: 01 02 03 04
                      过程: Encoding.ASCII.GetBytes(str);
                   ascii byte: 0x30 0x31 0x30 0x32 0x30 0x33 0x30 0x34
                （2）ascii byte => hex char => bin byte
                    ascii byte: 0x30 0x31 0x30 0x32 0x30 0x33 0x30 0x34
                      过程：Encoding.ASCII.GetString(bytes)
                    ascii: 01 02 03 04
                      过程: Convert.FromHexString(str)
                    byte: 0x01 0x02 0x03 0x04
            */

            //FINS_Serial_Test();
            //FINS_Serial_Test2();
            //FINS_Serial_Test3();
            FINS_Serial_Test4();
            //ModbusTest();
            //AlgorithmTest();
            //Mc3ETest();

            //HSMS_Test1();

            //ModbusAsciiTest();
            Console.ReadLine();
        }
        /*
         
         */
        static void ModbusAsciiTest()
        {
            ModbusMaster master = new ModbusASCII("COM1",9600,Parity.None,8,StopBits.One);
            master.Connect();
            byte[] buff = master.Read(1, "30003");
            master.Disconnect();
        }

        static void Mc3ETest()
        {
            MC3E mc = new MC3E();
            mc.Connect("192.168.196.132", 6000);
            //byte[] bytes = mc.Read("M0",1,Mitsubishi.Base.RequestType.BIT);
            //byte[] bytes = mc.Read("X0", 1, Mitsubishi.Base.RequestType.BIT);
            //byte[] bytes = mc.Read("X0", 1, Mitsubishi.Base.RequestType.WORD);
            //string res = string.Join(" ", bytes.Select(b => b.ToString("x2")));
            //Console.WriteLine(res);

            //mc.Write("M0",new byte[] { 0x01,0x01,0x01,0x01 }, Mitsubishi.Base.RequestType.BIT,LogCallback);
            //bytes = mc.Read("Y0", 1, Mitsubishi.Base.RequestType.WORD);
            //res = string.Join(" ", bytes.Select(b => b.ToString("x2")));
            //Console.WriteLine(res);

            //byte[] bytes = mc.Read("D0", 4, Mitsubishi.Base.RequestType.WORD);
            //mc.Write("D5", new byte[] { 0x7B, 0x00 }, Mitsubishi.Base.RequestType.WORD, LogCallback);
            //mc.Write("D5",new byte[] { 0x64,0x00,0x65,0x00,0x66,0x00,0x67,0x00 },Mitsubishi.Base.RequestType.WORD,LogCallback);

            //mc.PlcStop();
            //mc.PlcRun();

            //mc.Mc3E_Random_Bit_Write(new Mitsubishi.Base.DataParameter[]
            //{ 
            //    new Mitsubishi.Base.DataParameter() { Area = Mitsubishi.Base.Area.X, Address = "0", Data = new List<byte>() { 0x00 } },
            //    new Mitsubishi.Base.DataParameter() { Area = Mitsubishi.Base.Area.X, Address = "1", Data = new List<byte>() { 0x00 } },
            //    new Mitsubishi.Base.DataParameter() { Area = Mitsubishi.Base.Area.X, Address = "2", Data = new List<byte>() { 0x00 } },
            //    new Mitsubishi.Base.DataParameter() { Area = Mitsubishi.Base.Area.X, Address = "3", Data = new List<byte>() { 0x00 } },
            //    new Mitsubishi.Base.DataParameter() { Area = Mitsubishi.Base.Area.X, Address = "4", Data = new List<byte>() { 0x00 } },
            //    new Mitsubishi.Base.DataParameter() { Area = Mitsubishi.Base.Area.X, Address = "5", Data = new List<byte>() { 0x00 } },
            //    new Mitsubishi.Base.DataParameter() { Area = Mitsubishi.Base.Area.X, Address = "6", Data = new List<byte>() { 0x00 } },
            //    new Mitsubishi.Base.DataParameter() { Area = Mitsubishi.Base.Area.X, Address = "7", Data = new List<byte>() { 0x00 } },
            //});
            // 50 00 00 FF FF 03 00 16 00 10 00 02 14 00 00 01 01 00 00 00 9C A5 A5 00 00 00 9D FF A5 A5 A5
            //mc.Mc3E_Random_Word_Write(new List<Mitsubishi.Base.DataParameter>()
            //{
            //    new Mitsubishi.Base.DataParameter(){ Area = Mitsubishi.Base.Area.X, Address = "0", Data = new List<byte>(){ 0x01,0x00,0x01,0x00,0x00,0x01,0x00,0x01,0x01,0x00,0x01,0x00,0x00,0x01,0x00,0x01 }}
            //},
            //new List<Mitsubishi.Base.DataParameter>()
            //{
            //    new Mitsubishi.Base.DataParameter(){ Area = Mitsubishi.Base.Area.Y, Address = "0", Data = new List<byte>(){ 0x01,0x01,0x01,0x01, 0x01, 0x01, 0x01, 0x01, 0x01,0x00,0x01,0x00,0x00,0x01,0x00,0x01,0x01,0x00,0x01,0x00,0x00,0x01,0x00,0x01,0x01,0x00,0x01,0x00,0x00,0x01,0x00,0x01 }}
            //});

            // 50 00 00 FF FF 03 00 14 00 10 00 06 04 00 00 01 01 00 00 00 A8 05 00 00 00 00 9C 08 00
            mc.MultiBlockRead(
            new List<Mitsubishi.Base.DataParameter>()
            {
                new DataParameter(){ Area = Mitsubishi.Base.Area.D, Address = "0", Count = 5 }

            },null);
        }

        private static void LogCallback(object obj)
        {
            var bytes = obj as List<byte>;
            if (bytes == null) return;

            string res = string.Join(" ", bytes.Select(b => b.ToString("x2")));
            Console.WriteLine(res);
        }

        static void AlgorithmTest()
        {
            // 算法概述：
            // 组1：3,5,7,8
            //  res_data[5], idx = group[i] - group[0], val = res_data[idx]
            // 组2：16,18,19,20,21,23
            Dictionary<int, List<ushort>> OptimizedMap = new Dictionary<int, List<ushort>>();
            OptimizedMap[1] = new List<ushort>() { 3, 5, 7, 8, 16, 18, 19, 20, 21, 23 };

            List<RangeQueryCondition> rangeCondition = new List<RangeQueryCondition>();
            foreach (var key in OptimizedMap.Keys)
            {
                List<ushort> list = OptimizedMap[key];
                list.Sort();    // 默认从小到大排序
                RangeQueryCondition condition = null;
                for (int i = 0; i < list.Count; i++)
                {
                    if (i == 0)
                    {
                        condition = new RangeQueryCondition();
                        condition.SlaveId = (byte)key;
                        condition.Address = list[0];
                        condition.Count++;
                        rangeCondition.Add(condition);
                        continue;
                    }

                    if ((list[i] - 8) >= list[i - 1])
                    {
                        condition = new RangeQueryCondition();
                        condition.SlaveId = (byte)key;
                        condition.Address = list[i];
                        condition.Count++;
                        rangeCondition.Add(condition);
                        continue;
                    }

                    condition.Count = (ushort)(list[i] - condition.Address);
                }
            }

        }

        static void ModbusTest()
        {
            ModbusMaster modbus = new ModbusRTU("COM2", 9600, Parity.None, 8, StopBits.One);
            modbus.Connect();
            byte[] buff_00 = modbus.Read(1, "00001"); // IsBaseOne = false, 相当于取地址 0 
            byte[] buff_01 = modbus.Read(1, "00002"); // IsBaseOne = false, 相当于取地址 1

            modbus.Write(1, "00001", 2, new byte[] { 0x03 });
            modbus.Write(1, "00004", 2, new byte[] { 0x03 });

            buff_00 = modbus.Read(1, "00001"); // IsBaseOne = false, 相当于取地址 0 
            buff_01 = modbus.Read(1, "00002"); // IsBaseOne = false, 相当于取地址 1

            //byte[] buff1 = modbus.Read(1, "10001"); // IsBaseOne = false, 相当于取地址 0 
            //byte[] buff2 = modbus.Read(1, "10002"); // IsBaseOne = false, 相当于取地址 1

            //byte[] buff3 = modbus.Read(1, "30001"); // IsBaseOne = false, 相当于取地址 0
            //byte[] buff4 = modbus.Read(1, "30002"); // IsBaseOne = false, 相当于取地址 1

            //byte[] buff5 = modbus.Read(1, "40001"); // IsBaseOne = false, 相当于取地址 0
            //byte[] buff6 = modbus.Read(1, "40002"); // IsBaseOne = false, 相当于取地址 1

            //modbus.Write(1, "40001", 1, new byte[] { 0x00, 0x55 });
            //modbus.Write(1, "40002", 1, new byte[] { 0x00, 0x66 });

            //buff5 = modbus.Read(1, "40001"); // IsBaseOne = false, 相当于取地址 0
            //buff6 = modbus.Read(1, "40002"); // IsBaseOne = false, 相当于取地址 1
        }

        static void HexStringTest()
        {
            byte b = 0xC1;
            Console.WriteLine(b.ToString("X2"));    // C1

            string str = "007B007C";
            List<byte> buff = Convert.FromHexString(str).ToList();

            List<short> data = new List<short>();
            for (int i = 0; i < buff.Count; i += 2)
            {
                List<byte> item = buff.GetRange(i, 2);
                if (BitConverter.IsLittleEndian)
                    item.Reverse();
                data.Add(BitConverter.ToInt16(item.ToArray(), 0));
            }
        }

        static void FINS_Serial_Test()
        {
            /*
            SerialPort serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
            serialPort.Open();

            string unit_num = "00";
            ushort byte_addr = 0;
            byte bit_addr = 0;
            ushort count = 2;

            string cmd = $"@{unit_num}FA000000000010182" +
                $"{byte_addr.ToString("X4")}{bit_addr.ToString("X2")}{count.ToString("X4")}";
            // 计算 FCS 校验
            var fcs = FCS(cmd); // 7F
            cmd += fcs;
            // * \r
            cmd += "*\r";

            byte[] req = Encoding.ASCII.GetBytes(cmd);

            serialPort.Write(req, 0, req.Length);

            byte[] resp = new byte[serialPort.BytesToRead];
            serialPort.Read(resp, 0, resp.Length);
            string str_resp = Encoding.ASCII.GetString(resp);
            // resp: "@00FA 00 40 00 00 00 0101 0000(ErrorCode) 007C 0000 37 *\r"
            // resp: "@00FA 00 40 00 00 00 0101 0000(ErrorCode) 007B 007C 42 *\r"
            // status code 19 -> 4  起始位置 -> 偏移
            // data 23 ~ total_len - 4
            byte[] result = CheckFinsResp(str_resp,count,DataType.WORD);

            List<short> list = GetData<short>(result.ToList());
            */
            var fins = new Fins("COM1", 9600, Parity.None, 8, StopBits.One);
            fins.Open();
            byte[] datas = new byte[] { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 };
            fins.Write(0, OmronLib.Base.Area.CIO, 0, 0, OmronLib.Base.DataType.BIT, datas);
        }

        static void FINS_Serial_Test2()
        {
            var fins = new Fins("COM1", 9600, Parity.None, 8, StopBits.One);
            fins.Open();
            DateTime dateTime = fins.GetPlcClock(0);
        }

        static void FINS_Serial_Test3()
        {
            var fins = new Fins("COM1", 9600, Parity.None, 8, StopBits.One);
            fins.Open();
            // WORD 读取
            //List<byte> list1 = fins.Read(0,OmronLib.Base.Area.DM,0,0,8,OmronLib.Base.DataType.WORD);
            //List<byte> list2 = fins.Read(0, OmronLib.Base.Area.CIO, 0, 0, 8, OmronLib.Base.DataType.WORD);
            //List<byte> list3 = fins.Read(0, OmronLib.Base.Area.HR, 0, 0, 8, OmronLib.Base.DataType.WORD);

            List<byte> list4 = fins.Read(0, OmronLib.Base.Area.DM, 0, 0, 16, OmronLib.Base.DataType.BIT);
            List<byte> list5 = fins.Read(0, OmronLib.Base.Area.CIO, 0, 0, 16, OmronLib.Base.DataType.BIT);
            List<byte> list6 = fins.Read(0, OmronLib.Base.Area.HR, 0, 0, 16, OmronLib.Base.DataType.BIT);
            List<byte> list7 = fins.Read(0, OmronLib.Base.Area.WR, 0, 0, 8, OmronLib.Base.DataType.WORD);
        }

        static void FINS_Serial_Test4()
        {
            var fins = new Fins("COM1", 9600, Parity.None, 8, StopBits.One);
            fins.Open();

            //byte[] datas = new byte[] { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,0x00,0x05,0x00,0x06,0x00,0x07,0x00,0x7D };
            //fins.Write(0, OmronLib.Base.Area.DM, 0, 0, OmronLib.Base.DataType.WORD, datas);


            //byte[] datas = new byte[] { 0x00, 0x7A, 0x00, 0x7B, 0x00, 0x7C, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x7F, 0x00,0X80,0x00,0X81 };
            //fins.Write(0, OmronLib.Base.Area.CIO, 0, 0, OmronLib.Base.DataType.WORD, datas);
            //fins.Write(0, OmronLib.Base.Area.HR, 0, 0, OmronLib.Base.DataType.WORD, datas);

            byte[] datas = new byte[] { 0x01,0x01,0x01,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
            fins.Write(0,OmronLib.Base.Area.WR,0,0,OmronLib.Base.DataType.BIT, datas);
        }

        static void HSMS_Test1()
        {
            HSMS HSMS = new HSMS();
            HSMS.Connect("192.168.196.132", 5000);
            SecsGemLib.Base.Message msg = HSMS.S1F1();
            SecsGemLib.Base.Message msg2 = HSMS.S1F3(123);
        }
    }

    class RangeQueryCondition
    {
        public byte SlaveId { get; set; }
        public FunctionType FuncType { get; set; }
        public ushort Address { get; set; }
        public ushort Count { get; set; }
    }
}